package com.abigdreamer.swing.app.autoupdate;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;

public class FileTransProc extends AUpdSrvProc {

	private Config config = Config.getInstance();// 配置文件对像
	private ClientVerParser cvPaser = null;
	private HashMap<String, UpdFile> cFiles = new HashMap<String, UpdFile>();

	public FileTransProc(Socket socket) {
		super(socket);

		registeCmd(AUPD.SEND_CLIENT_VERSION, "receiveClientVer");// 数据内容

		registeCmd(AUPD.SEND_CLIENT_VERSION, "receiveClientVer");// 数据内容

		registeCmd(AUPD.READY_TO_UPDATE, "readyToUpdate");// 客户端已经准备好更新了
	}

	/**
	 * 接收客户端的升级请求，并进行处理
	 */
	public void run() {
		config.refresh();// 重新更新配置信息
		super.run();
	}

	public String readyToUpdate() {
		Config.print(socket.getInetAddress() + ":客户端已经准备好接收更新文件");
		int ret = sendUpdateFile();
		switch (ret) {
		case 0:
			return AUPD.UPDATED_FAILURE;// 失败
		case 1:
			return AUPD.UPDATED_SUCCESSFUL;// 成功
		default:
			return AUPD.NOTNEED_UPDATED;// 无需更新
		}
	}

	/**
	 * @return 0.更新失败 1.更新成功 2.无需更新
	 */
	private int sendUpdateFile() {
		try {
			// 检查服务器和客户端版本号是否一致，如果一致辞，则无需升级
			if (config.getVerstion().equals(cvPaser.getVerstion())) {
				Config.print(socket.getInetAddress() + ":版本一致，无需更新");
				return 2;
			}
			// 开始进行处理
			UpdFile srvFiles[] = config.getFiles();
			boolean isSuccess = true;
			for (int i = 0; i < srvFiles.length; i++) {
				UpdFile cf = (UpdFile) cFiles.get(srvFiles[i].getName());
				// 文件不存在或版本号不一致则需要更新该文件
				if (cf == null || !cf.getVersion().equals(srvFiles[i].getVersion())) {
					if (!sendFile(srvFiles[i])) {
						isSuccess = false;
					}
				}
			}// END for
				// 发送版本信息文件，发送更新信息文件
			if (isSuccess) {
				UpdFile verFile = new UpdFile("autoupdate.xml");
				verFile.setPath("." + File.separator + "config");
				verFile.setType(0);
				verFile.setVersion(config.getVerstion());
				if (!sendFile(verFile)) {
					Config.print(socket.getInetAddress() + ":发送版本文件失败");
					return 0;
				}
				// 发送更新信息
				UpdFile infFile = new UpdFile("history.htm");
				infFile.setPath("." + File.separator + "config");
				infFile.setType(0);
				infFile.setVersion(config.getVerstion());
				if (!sendFile(infFile)) {
					Config.print(socket.getInetAddress() + ":发送最新信息失败");
				}
				return 1;
			} else {
				return 0;
			}
		} catch (Exception e) {
			Config.print("处理需要更新文件失败," + e);
			e.printStackTrace();
			return 0;
		}
	}

	/**
	 * 第一位表示是数据内容还是结束内容
	 * 
	 * @author Darkness
	 * @date 2011-12-29 上午11:44:24
	 * @version V1.0
	 * @param flag
	 */
	public void receiveClientVer() {
		try {
			byte[] resultData = FileContract.unpacking(socketIn);
			if (resultData!= null) {// 成功
				socketOut.write(Config.packingCmd(AUPD.RECEIVED_CLIENT_VERSION));// 临时测试
				Config.print("接收客户端" + socket.getInetAddress() + " 版本信息成功");
				cvPaser = new ClientVerParser(new StringReader(new String(resultData)));
				UpdFile files[] = cvPaser.getFiles();
				for (int i = 0; i < files.length; i++) {
					cFiles.put(files[i].getName(), files[i]);
				}
			} else {// 失败
				bye();// 结束
			}
		} catch (Exception e) {
			Config.print("接收客户端" + socket.getInetAddress() + " 版本号信息处理失败," + e);
		}
	}
	
	private void bye() throws IOException {
		socketOut.write(Config.packingCmd(AUPD.BYE));
	}

	// 0.失败 1.成功
	private boolean sendFileAbsPath(String path) {
		try {
			
			List<byte[]> packedData = FileContract.packing(path);
			for (byte[] bs : packedData) {
				socketOut.write(bs);
			}
			socketOut.flush();
			
			String cmd = FileContract.unpackingCmd(socketIn);
			if (cmd == null) {
				Config.print(socket.getInetAddress() + ":读取命令失败,CMD=" + cmd);
				bye();// 结束
				return false;
			}
			
			if (cmd.equals(AUPD.RECEIVED_FILE_ABSOULT)) {// 成功
				Config.print(socket.getInetAddress() + ":接收文件路径成功," + path);
				return true;
			} else if (cmd.equals(AUPD.BYE)) {// 失败
				Config.print(socket.getInetAddress() + ":接收文件路径失败，" + path);
				return false;
			} else {// 异常
				return false;
			}
		} catch (Exception e) {
			Config.print(socket.getInetAddress() + ":发送文件路径失败," + path);
			e.printStackTrace();
			return false;
		}
	}
	
	// false.失败 true.成功
	private boolean sendFile(UpdFile file) {
		try {
			File f = new File(Config.formatPath(file.getPath()) + file.getName());
			if (!f.exists() || !f.isFile()) {
				Config.print(file + ",不存在，无法更新");
				return false;
			}
			Config.print(socket.getInetAddress() + ":开始传输文件>>" + file);
			socketOut.write(Config.packingCmd(AUPD.SEND_FILE_ABSOULT));// 发送文件全路径
			String fileAbsPath = Config.formatPath(file.getPath()) + file.getName();
			if (!sendFileAbsPath(fileAbsPath)) {
				return false;
			}
			
			socketOut.write(Config.packingCmd(AUPD.START_TRANSMIT));// 开始传输
			
			List<byte[]> packedData = FileContract.packing(f);
			for (byte[] bs : packedData) {
				socketOut.write(bs);
			}
			socketOut.flush();
			
			String cmd = FileContract.unpackingCmd(socketIn);
			if (cmd == null) {
				Config.print(socket.getInetAddress() + ":读取命令失败,CMD=" + cmd);
				bye();// 结束
				return false;
			}
			
			if (cmd.equals(AUPD.TERMINATE_TRANSMIT)) {// 成功
				Config.print(socket.getInetAddress() + ":传输文件'" + file + "'成功");
				return true;
			} else if (cmd.equals(AUPD.BYE)) {// 失败
				Config.print(socket.getInetAddress() + ":传输文件失败，" + file);
				return false;
			} else {// 异常
				Config.print(socket.getInetAddress() + ":传输文件异常，" + file + "," + cmd);
				return false;
			}
		} catch (Exception e) {
			Config.print("传输文件'" + file + "'失败," + e);
			e.printStackTrace();
			return false;
		}
	}
}
